// ----------------------------------------
// Filename: Link_List.c
// Description: The code that implements a bi-directional linked list
// Author: Jon Maloney
// Date: 9-May-2012
//

//************************************************************
//                    Include .h files
//************************************************************
#include "Linked_List.h"
#include <stdlib.h>
//************************************************************
//                    Include external references
//************************************************************

//************************************************************
//                    Define Statements
//************************************************************

//************************************************************
//                    Struct, Union, enum Statements
//************************************************************

//************************************************************
//                    Global variables and constants
//************************************************************

//************************************************************
//                    Prototype Private Functions
//************************************************************

//************************************************************
//                    Implementation
//************************************************************

// ----------------------------------------
// LinkList_Add
// 
// Adds an Node to a link list.
//	If a new list Node needs to be created
//	this function will create the new list Node
//	and return this list Node's handle.
// Input:
// 	currentListNode: 	the list Node that the new Node is to be inserted into.
//							If currentListNode is NULL a new list node will be 
//							created and the currentListNode pointer will be 
//							re-directed to this new list node. 
//	newItem:			The item that is to be inserted into the list.
// Output:
//  A handle to the link list that was created.
// Conditions:
// 	none
//
linkedList_Handle LinkedList_Add( linkedList_Handle currentListNode, void * newItem )
{
	linkedList_Handle newListNode;
	
	//If the current list node is null then the list is empty
	if(currentListNode == NULL)	
	{	
		//Create a new listNode
		currentListNode = (linkedList_Handle)malloc(sizeof(TLINKED_LIST));
		currentListNode->Item			= newItem;
		currentListNode->NextNode		= currentListNode;
		currentListNode->PreviousNode 	= currentListNode;
		return currentListNode;
	}
	else
	{
		//Create a new listNode
		newListNode = (linkedList_Handle)malloc(sizeof(TLINKED_LIST));
	
		if(newListNode == NULL)
			return NULL;
		
		//Add the Node to the list.
		newListNode->Item = newItem;
	
		//Add the list to the link list
		currentListNode = LinkedList_Insert(currentListNode, newListNode);

		return currentListNode;
	}	
}

// ----------------------------------------
// LinkedList_Insert
// 
// Inserts a new list Node into a current lits.
// Input:
// 	currentListNode: 	The list Node that the new list Node is to be inserted into.
//	newListNode:		The list Node that is to be inserted into the list.
// Output:
//  none
// Conditions:
// 	none
//
linkedList_Handle LinkedList_Insert(linkedList_Handle currentListNode, linkedList_Handle newListNode)
{
	//Add the newNode to the link List
	ENTER_CRITICAL();
	{
		if(currentListNode != NULL)
		{
			//The new list Node's previous Node is the current list Node
			newListNode->NextNode = currentListNode;
		
			//The new list's previous Node is the current list's previous node.
			newListNode->PreviousNode = currentListNode->PreviousNode;
		
			//The pointer to the previous list Node in the current list Node needs
			//	to point to the new list Node. 
			currentListNode->PreviousNode->NextNode = newListNode;
		
			//The pointer to the next Node in the current list Node needs to 
			//	point to the new list Node.
			currentListNode->PreviousNode = newListNode;
		} 
		else 
		{
			currentListNode	= newListNode;
			currentListNode->NextNode		= currentListNode;
			currentListNode->PreviousNode 	= currentListNode;
		}
	}
	EXIT_CRITICAL();
	return currentListNode;
}

// ----------------------------------------
// LinkedList_Remove
// 
// Removes an Node from the link list.
//	(DOES not delete the node)
//		See LinkList_Delete for a delete and remove function
// Input:
// 	listNodeToRemove:	The link list Node to be removed from the link list
// Output:
//  pdTRUE 	if there are elements remaining in the linked list
//	pdFALSE	if there are NO elements remaining in the linked list.
// Conditions:
// 	none
//
BOOL LinkedList_Remove(linkedList_Handle ListNodeToRemove)
{
	//Remove Node from List
	
	//If this is not the last Node in the list
	if(ListNodeToRemove->NextNode != ListNodeToRemove)
	{
		//Update the elements links
		//Ensure another Node isnt added to the link list before we are finished removing this element
		ENTER_CRITICAL();
		{
			//My previous's next is equal to my next
			ListNodeToRemove->PreviousNode->NextNode = ListNodeToRemove->NextNode;
			//My next's previous is equal to my previous
			ListNodeToRemove->NextNode->PreviousNode = ListNodeToRemove->PreviousNode;
		}
		EXIT_CRITICAL();

		return pdTRUE;
	}

	return pdFALSE;
}

// ----------------------------------------
// LinkedList_DeleteNode
// 
// Removes an Node from the link list and free's the memory allocated to the Node
//	and frees the memory allocated to the Item in the node.
// Input:
// 	ListNodeToDelete:	The link list Node to be removed from the link list
// Output:
//  pdTRUE 	if there are elements remaining in the linked list
//	pdFALSE	if there are NO elements remaining in the linked list.
// Conditions:
// 	none
//
BOOL LinkedList_DeleteNode(linkedList_Handle ListNodeToDelete)
{
	BOOL returnVar;
	
	//Remove the task from the list.
	returnVar = LinkedList_Remove(ListNodeToDelete);

	//Free up the memory of the Node in the list
	free( ListNodeToDelete->Item );
	
	ListNodeToDelete->PreviousNode = 0;
	ListNodeToDelete->NextNode = 0;
	ListNodeToDelete->Item = 0;	

	//Free up the memory of the list Node to be removed	
	free( ListNodeToDelete );
	
	//Make sure the pointer is nulled.
	ListNodeToDelete = NULL;

	return returnVar;
}

// ----------------------------------------
// LinkedList_Move
// 
// Moves an Node from one list to another
// Input:
//  moveFrom: 	The list that the task is to be moved from
//	moveTo:		The list that the task to the be moved into
// Output:
//  none
// Conditions:
// 	none
//
BOOL LinkedList_Move(linkedList_Handle moveFrom, linkedList_Handle moveTo )
{
	BOOL returnVar;
	
	if(moveFrom == moveTo)//If both pointers are pointing to the same memory
		return pdFALSE;	//The list Node doesnt need to be moved
	
	//Take the Node out of its current position
	returnVar = LinkedList_Remove(moveFrom);
	
	//Place the node into its new position
	moveFrom = LinkedList_Insert(moveFrom, moveTo);
	
	return returnVar;
}
